Implement gdk_window_set_icon_list() for Win32, with support for big and
authorTim Evans <t.evans@aranz.com>
Sun, 14 Dec 2003 01:06:56 +0000 (01:06 +0000)
committerTor Lillqvist <tml@src.gnome.org>
Sun, 14 Dec 2003 01:06:56 +0000 (01:06 +0000)
Tue Dec  8 09:41:00 2003  Tim Evans  <t.evans@aranz.com>

* gdk/win32/gdkwindow-win32.[ch]: Implement
gdk_window_set_icon_list() for Win32, with support for big and
small icons and support for alpha-channel icons under Windows
XP. Replaces the previous implementation of gdk_window_set_icon().
(#128762)

ChangeLog
ChangeLog.pre-2-10
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
gdk/win32/gdkwindow-win32.c
gdk/win32/gdkwindow-win32.h

index 331ed52938600ee07a14b5314002c2bf94e7f970..5409d88c3b409abe6f12c42e64927dd7cf87ed11 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Tue Dec  8 09:41:00 2003  Tim Evans  <t.evans@aranz.com>
+
+       * gdk/win32/gdkwindow-win32.[ch]: Implement
+       gdk_window_set_icon_list() for Win32, with support for big and
+       small icons and support for alpha-channel icons under Windows
+       XP. Replaces the previous implementation of gdk_window_set_icon().
+       (#128762)
+       
 Sun Dec 14 01:28:23 2003  Matthias Clasen  <maclas@gmx.de>
 
        * gdk/x11/gdkprivate-x11.h: 
index 331ed52938600ee07a14b5314002c2bf94e7f970..5409d88c3b409abe6f12c42e64927dd7cf87ed11 100644 (file)
@@ -1,3 +1,11 @@
+Tue Dec  8 09:41:00 2003  Tim Evans  <t.evans@aranz.com>
+
+       * gdk/win32/gdkwindow-win32.[ch]: Implement
+       gdk_window_set_icon_list() for Win32, with support for big and
+       small icons and support for alpha-channel icons under Windows
+       XP. Replaces the previous implementation of gdk_window_set_icon().
+       (#128762)
+       
 Sun Dec 14 01:28:23 2003  Matthias Clasen  <maclas@gmx.de>
 
        * gdk/x11/gdkprivate-x11.h: 
index 331ed52938600ee07a14b5314002c2bf94e7f970..5409d88c3b409abe6f12c42e64927dd7cf87ed11 100644 (file)
@@ -1,3 +1,11 @@
+Tue Dec  8 09:41:00 2003  Tim Evans  <t.evans@aranz.com>
+
+       * gdk/win32/gdkwindow-win32.[ch]: Implement
+       gdk_window_set_icon_list() for Win32, with support for big and
+       small icons and support for alpha-channel icons under Windows
+       XP. Replaces the previous implementation of gdk_window_set_icon().
+       (#128762)
+       
 Sun Dec 14 01:28:23 2003  Matthias Clasen  <maclas@gmx.de>
 
        * gdk/x11/gdkprivate-x11.h: 
index 331ed52938600ee07a14b5314002c2bf94e7f970..5409d88c3b409abe6f12c42e64927dd7cf87ed11 100644 (file)
@@ -1,3 +1,11 @@
+Tue Dec  8 09:41:00 2003  Tim Evans  <t.evans@aranz.com>
+
+       * gdk/win32/gdkwindow-win32.[ch]: Implement
+       gdk_window_set_icon_list() for Win32, with support for big and
+       small icons and support for alpha-channel icons under Windows
+       XP. Replaces the previous implementation of gdk_window_set_icon().
+       (#128762)
+       
 Sun Dec 14 01:28:23 2003  Matthias Clasen  <maclas@gmx.de>
 
        * gdk/x11/gdkprivate-x11.h: 
index 331ed52938600ee07a14b5314002c2bf94e7f970..5409d88c3b409abe6f12c42e64927dd7cf87ed11 100644 (file)
@@ -1,3 +1,11 @@
+Tue Dec  8 09:41:00 2003  Tim Evans  <t.evans@aranz.com>
+
+       * gdk/win32/gdkwindow-win32.[ch]: Implement
+       gdk_window_set_icon_list() for Win32, with support for big and
+       small icons and support for alpha-channel icons under Windows
+       XP. Replaces the previous implementation of gdk_window_set_icon().
+       (#128762)
+       
 Sun Dec 14 01:28:23 2003  Matthias Clasen  <maclas@gmx.de>
 
        * gdk/x11/gdkprivate-x11.h: 
index 7f28f8ae0cec40a3430ce4a9ee0be6cd043f57b7..73985006114e83989a1a748bc190109e52b204a6 100644 (file)
 #include "gdkprivate-win32.h"
 #include "gdkinput-win32.h"
 
+#ifdef __MINGW32__
+typedef struct { 
+  DWORD        bV5Size; 
+  LONG         bV5Width; 
+  LONG         bV5Height; 
+  WORD         bV5Planes; 
+  WORD         bV5BitCount; 
+  DWORD        bV5Compression; 
+  DWORD        bV5SizeImage; 
+  LONG         bV5XPelsPerMeter; 
+  LONG         bV5YPelsPerMeter; 
+  DWORD        bV5ClrUsed; 
+  DWORD        bV5ClrImportant; 
+  DWORD        bV5RedMask; 
+  DWORD        bV5GreenMask; 
+  DWORD        bV5BlueMask; 
+  DWORD        bV5AlphaMask; 
+  DWORD        bV5CSType; 
+  CIEXYZTRIPLE bV5Endpoints; 
+  DWORD        bV5GammaRed; 
+  DWORD        bV5GammaGreen; 
+  DWORD        bV5GammaBlue; 
+  DWORD        bV5Intent; 
+  DWORD        bV5ProfileData; 
+  DWORD        bV5ProfileSize; 
+  DWORD        bV5Reserved; 
+} BITMAPV5HEADER;
+
+#endif
+
+#if 0
 #include <gdk-pixbuf/gdk-pixbuf.h>
-#include <stdio.h> /* sprintf */
+#include <stdio.h>
+#endif
 
 static GdkColormap* gdk_window_impl_win32_get_colormap (GdkDrawable *drawable);
 static void         gdk_window_impl_win32_set_colormap (GdkDrawable *drawable,
@@ -92,7 +124,8 @@ gdk_window_impl_win32_init (GdkWindowImplWin32 *impl)
   impl->height = 1;
 
   impl->hcursor = NULL;
-  impl->hicon = NULL;
+  impl->hicon_big = NULL;
+  impl->hicon_small = NULL;
   impl->hint_flags = 0;
   impl->extension_events_selected = FALSE;
 }
@@ -142,10 +175,15 @@ gdk_window_impl_win32_finalize (GObject *object)
       GDI_CALL (DestroyCursor, (window_impl->hcursor));
       window_impl->hcursor = NULL;
     }
-  if (window_impl->hicon != NULL)
+  if (window_impl->hicon_big != NULL)
+    {
+      GDI_CALL (DestroyIcon, (window_impl->hicon_big));
+      window_impl->hicon_big = NULL;
+    }
+  if (window_impl->hicon_small != NULL)
     {
-      GDI_CALL (DestroyIcon, (window_impl->hicon));
-      window_impl->hicon = NULL;
+      GDI_CALL (DestroyIcon, (window_impl->hicon_small));
+      window_impl->hicon_small = NULL;
     }
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
@@ -2169,121 +2207,284 @@ gdk_window_set_accept_focus (GdkWindow *window,
     private->accept_focus = accept_focus;
 }
 
-void          
-gdk_window_set_icon_list (GdkWindow *window,
-                         GList     *pixbufs)
+static HICON
+pixbuf_to_hicon_alpha_winxp (GdkWindow *window,
+                            GdkPixbuf *pixbuf)
 {
-  g_return_if_fail (GDK_IS_WINDOW (window));
+  /* Based on code from
+   * http://www.dotnet247.com/247reference/msgs/13/66301.aspx
+   */
+  HDC hdc;
+  BITMAPV5HEADER bi;
+  HBITMAP hBitmap, hMonoBitmap;
+  guchar *indata, *inrow;
+  guchar *outdata, *outrow;
+  HICON hAlphaIcon = NULL;
+  ICONINFO ii;
+  gint width, height, i, j, rowstride;
 
-  if (GDK_WINDOW_DESTROYED (window))
-    return;
+  if (pixbuf == NULL)
+    return NULL;
 
-  /* We could convert it to a hIcon and DrawIcon () it when getting
-   * a WM_PAINT with IsIconic, but is it worth it ? Same probably
-   * goes for gdk_window_set_icon (). Patches accepted :-)  --hb
-   * Or do we only need to deliver the Icon on WM_GETICON ?
+  width = gdk_pixbuf_get_width (pixbuf); /* width of icon */
+  height = gdk_pixbuf_get_height (pixbuf); /* height of icon */
+
+  ZeroMemory (&bi, sizeof (BITMAPV5HEADER));
+  bi.bV5Size = sizeof (BITMAPV5HEADER);
+  bi.bV5Width = width;
+  bi.bV5Height = height;
+  bi.bV5Planes = 1;
+  bi.bV5BitCount = 32;
+  bi.bV5Compression = BI_BITFIELDS;
+  /* The following mask specification specifies a supported 32 BPP
+   * alpha format for Windows XP (BGRA format).
    */
+  bi.bV5RedMask   = 0x00FF0000;
+  bi.bV5GreenMask = 0x0000FF00;
+  bi.bV5BlueMask  = 0x000000FF;
+  bi.bV5AlphaMask = 0xFF000000;
+
+  /* Create the DIB section with an alpha channel. */
+  hdc = GetDC (NULL);
+  hBitmap = CreateDIBSection (hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS,
+                             (void **)&outdata, NULL, (DWORD)0);
+  ReleaseDC (NULL, hdc);
+
+  /* Draw something on the DIB section */
+  indata = gdk_pixbuf_get_pixels (pixbuf);
+  rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+  for (j=0; j<height; j++)
+    {
+      outrow = outdata + 4*j*width;
+      inrow  = indata  + (height-j-1)*rowstride;
+      for (i=0; i<width; i++)
+       {
+         outrow[4*i+0] = inrow[4*i+2];
+         outrow[4*i+1] = inrow[4*i+1];
+         outrow[4*i+2] = inrow[4*i+0];
+         outrow[4*i+3] = inrow[4*i+3];
+       }
+    }
+
+  /* Create an empty mask bitmap */
+  hMonoBitmap = CreateBitmap (width, height, 1, 1, NULL);
+
+  ii.fIcon = TRUE;
+  ii.xHotspot = 0;
+  ii.yHotspot = 0;
+  ii.hbmMask = hMonoBitmap;
+  ii.hbmColor = hBitmap;
+
+  /* Create the alpha cursor with the alpha DIB section */
+  hAlphaIcon = CreateIconIndirect (&ii);
+
+  GDI_CALL (DeleteObject, (hBitmap));
+  GDI_CALL (DeleteObject, (hMonoBitmap));
+
+  return hAlphaIcon;
 }
 
-void          
-gdk_window_set_icon (GdkWindow *window, 
-                    GdkWindow *icon_window,
-                    GdkPixmap *pixmap,
-                    GdkBitmap *mask)
+static HICON
+pixbuf_to_hicon_normal (GdkWindow *window,
+                       GdkPixbuf *pixbuf)
 {
+  GdkPixmap *pixmap;
+  GdkBitmap *mask;
+  HBITMAP hbmmask = NULL;
   ICONINFO ii;
   HICON hIcon;
   gint w = 0, h = 0;
-  GdkWindowImplWin32 *impl;
-
-  g_return_if_fail (window != NULL);
-  g_return_if_fail (GDK_IS_WINDOW (window));
-
-  if (GDK_WINDOW_DESTROYED (window))
-    return;
 
-  impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
+  if (pixbuf == NULL)
+    return NULL;
 
-  if (pixmap)
-    {
-      static int num = 0;
-      HBITMAP hbmmask = NULL;
+  /* create a normal icon with a bitmap mask */
+  w = gdk_pixbuf_get_width (pixbuf);
+  h = gdk_pixbuf_get_height (pixbuf);
+  gdk_pixbuf_render_pixmap_and_mask_for_colormap (pixbuf, 
+                                                 gdk_drawable_get_colormap (window),
+                                                 &pixmap,
+                                                 &mask,
+                                                 128);
 
-      gdk_drawable_get_size (GDK_DRAWABLE(pixmap), &w, &h);
+  /* we need the inverted mask for the XOR op */
+  {
+    HDC hdc1 = CreateCompatibleDC (NULL);
+    HBITMAP hbmold1;
 
-      /* we need the inverted mask for the XOR op */
+    hbmmask = CreateCompatibleBitmap (hdc1, w, h);
+    hbmold1 = SelectObject (hdc1, hbmmask);
+    if (mask)
+      {
+       HDC hdc2 = CreateCompatibleDC (NULL);
+       HBITMAP hbmold2 = SelectObject (hdc2, GDK_PIXMAP_HBITMAP (mask));
+       GDI_CALL (BitBlt, (hdc1, 0,0,w,h, hdc2, 0,0, NOTSRCCOPY));
+       GDI_CALL (SelectObject, (hdc2, hbmold2));
+       GDI_CALL (DeleteDC, (hdc2));
+      }
+    else
       {
-        HDC hdc1 = CreateCompatibleDC (NULL);
-        HBITMAP hbmold1;
-
-        hbmmask = CreateCompatibleBitmap (hdc1, w, h);
-        hbmold1 = SelectObject (hdc1, hbmmask);
-        if (mask)
-          {
-            HDC hdc2 = CreateCompatibleDC (NULL);
-            HBITMAP hbmold2 = SelectObject (hdc2, GDK_PIXMAP_HBITMAP (mask));
-            GDI_CALL (BitBlt, (hdc1, 0,0,w,h, hdc2, 0,0, NOTSRCCOPY));
-            GDI_CALL (SelectObject, (hdc2, hbmold2));
-            GDI_CALL (DeleteDC, (hdc2));
-          }
-        else
-          {
-            RECT rect;
-            GetClipBox (hdc1, &rect);
-            GDI_CALL (FillRect, (hdc1, &rect, GetStockObject (WHITE_BRUSH)));
-          }
-        GDI_CALL (SelectObject, (hdc1, hbmold1));
-        GDI_CALL (DeleteDC, (hdc1));
+       RECT rect;
+       GetClipBox (hdc1, &rect);
+       GDI_CALL (FillRect, (hdc1, &rect, GetStockObject (BLACK_BRUSH)));
       }
+    GDI_CALL (SelectObject, (hdc1, hbmold1));
+    GDI_CALL (DeleteDC, (hdc1));
+  }
+
+  ii.fIcon = TRUE;
+  ii.xHotspot = ii.yHotspot = 0; /* ignored for icons */
+  ii.hbmMask = hbmmask;
+  ii.hbmColor = GDK_PIXMAP_HBITMAP (pixmap);
+  hIcon = CreateIconIndirect (&ii);
+  if (!hIcon)
+    WIN32_API_FAILED ("CreateIconIndirect");
+  GDI_CALL (DeleteObject, (hbmmask));
 
-      ii.fIcon = TRUE;
-      ii.xHotspot = ii.yHotspot = 0; /* ignored for icons */
-      ii.hbmMask = hbmmask;
-      ii.hbmColor = GDK_PIXMAP_HBITMAP (pixmap); 
-      hIcon = CreateIconIndirect (&ii);
-      if (!hIcon)
-        WIN32_API_FAILED ("CreateIconIndirect");
-      GDI_CALL (DeleteObject, (hbmmask));
 #if 0 /* to debug pixmap and mask setting */
+  {
+    static int num = 0;
+    GdkPixbuf* pixbuf = NULL;
+    char name[256];
+
+    pixbuf = gdk_pixbuf_get_from_drawable (NULL, pixmap, NULL, 0, 0, 0, 0, w, h);
+    if (pixbuf)
       {
-        GdkPixbuf* pixbuf = NULL;
-        char name[256];
-
-        pixbuf = gdk_pixbuf_get_from_drawable (NULL, pixmap, NULL, 0, 0, 0, 0, w, h);
-       if (pixbuf)
-          {
-            num = (num + 1) % 999; /* restrict maximim number */
-            sprintf (name, "c:\\temp\\ico%03dpixm.png", num); 
-            gdk_pixbuf_save (pixbuf, name, "png", NULL, NULL);
-            gdk_pixbuf_unref (pixbuf);
-          }
-        pixbuf = !mask ? NULL : gdk_pixbuf_get_from_drawable (NULL, mask, NULL, 0, 0, 0, 0, w, h);
-       if (pixbuf)
-          {
-            sprintf (name, "c:\\temp\\ico%03dmask.png", num); 
-            gdk_pixbuf_save (pixbuf, name, "png", NULL, NULL);
-            gdk_pixbuf_unref (pixbuf);
-          }
+       num = (num + 1) % 999; /* restrict maximim number */
+       sprintf (name, "c:\\temp\\ico%03dpixm.png", num); 
+       gdk_pixbuf_save (pixbuf, name, "png", NULL, NULL);
+       gdk_pixbuf_unref (pixbuf);
       }
+  }
 #endif
 
-      SendMessage (GDK_WINDOW_HWND (window), WM_SETICON, ICON_BIG, (LPARAM)hIcon);
-      if (impl->hicon)
-        GDI_CALL (DestroyIcon, (impl->hicon));
-      impl->hicon = hIcon;
+  if (pixmap)
+    g_object_unref (G_OBJECT (pixmap));
+  if (mask)
+    g_object_unref (G_OBJECT (mask));
+
+  return hIcon;
+}
+
+static HICON
+pixbuf_to_hicon (GdkWindow *window,
+                GdkPixbuf *pixbuf)
+{
+  static gboolean is_win_xp=FALSE, is_win_xp_checked=FALSE;
+
+  if (!is_win_xp_checked)
+    {
+      OSVERSIONINFO version;
+
+      is_win_xp_checked = TRUE;
+      memset (&version, 0, sizeof (version));
+      version.dwOSVersionInfoSize = sizeof (version);
+      is_win_xp = GetVersionEx (&version)
+       && version.dwPlatformId == VER_PLATFORM_WIN32_NT
+       && (version.dwMajorVersion > 5
+           || (version.dwMajorVersion == 5 && version.dwMinorVersion >= 1));
     }
+
+  if (pixbuf == NULL)
+    return NULL;
+
+  if (is_win_xp && gdk_pixbuf_get_has_alpha (pixbuf))
+    return pixbuf_to_hicon_alpha_winxp (window, pixbuf);
   else
-    {
-      /* reseting to default icon */
-      if (impl->hicon)
-        {
-          SendMessage (GDK_WINDOW_HWND (window), WM_SETICON, ICON_BIG, 0);
-          GDI_CALL (DestroyIcon, (impl->hicon));
-          impl->hicon = NULL;
-        }
+    return pixbuf_to_hicon_normal (window, pixbuf);
+}
+
+void          
+gdk_window_set_icon_list (GdkWindow *window,
+                         GList     *pixbufs)
+{
+  GdkPixbuf *pixbuf, *big_pixbuf, *small_pixbuf;
+  gint big_diff, small_diff;
+  gint big_w, big_h, small_w, small_h;
+  gint w, h;
+  gint dw, dh, diff;
+  HICON small_hicon, big_hicon;
+  GdkWindowImplWin32 *impl;
+  gint i, big_i, small_i;
+
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  if (GDK_WINDOW_DESTROYED (window))
+    return;
+
+  impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
+
+  /* ideal sizes for small and large icons */
+  big_w = GetSystemMetrics (SM_CXICON);
+  big_h = GetSystemMetrics (SM_CYICON);
+  small_w = GetSystemMetrics (SM_CXSMICON);
+  small_h = GetSystemMetrics (SM_CYSMICON);
+
+  /* find closest sized icons in the list */
+  big_pixbuf = NULL;
+  small_pixbuf = NULL;
+  big_diff = 0;
+  small_diff = 0;
+  i = 0;
+  while (pixbufs)
+    {
+      pixbuf = (GdkPixbuf*) pixbufs->data;
+      w = gdk_pixbuf_get_width (pixbuf);
+      h = gdk_pixbuf_get_height (pixbuf);
+
+      dw = ABS (w - big_w);
+      dh = ABS (h - big_h);
+      diff = dw*dw + dh*dh;
+      if (big_pixbuf == NULL || diff < big_diff)
+       {
+         big_pixbuf = pixbuf;
+         big_diff = diff;
+         big_i = i;
+       }
+
+      dw = ABS(w - small_w);
+      dh = ABS(h - small_h);
+      diff = dw*dw + dh*dh;
+      if (small_pixbuf == NULL || diff < small_diff)
+       {
+         small_pixbuf = pixbuf;
+         small_diff = diff;
+         small_i = i;
+       }
+
+      pixbufs = g_list_next (pixbufs);
+      i++;
     }
 
-  GDK_NOTE (MISC, g_print ("gdk_window_set_icon: %p: %p %dx%d\n", GDK_WINDOW_HWND (window), impl->hicon, w, h));
+  /* Create the icons */
+  big_hicon = pixbuf_to_hicon (window, big_pixbuf);
+  small_hicon = pixbuf_to_hicon (window, small_pixbuf);
+
+  /* Set the icons */
+  SendMessage (GDK_WINDOW_HWND (window), WM_SETICON, ICON_BIG,
+              (LPARAM)big_hicon);
+  SendMessage (GDK_WINDOW_HWND (window), WM_SETICON, ICON_SMALL,
+              (LPARAM)small_hicon);
+
+  /* Store the icons, destroying any previous icons */
+  if (impl->hicon_big)
+    GDI_CALL (DestroyIcon, (impl->hicon_big));
+  impl->hicon_big = big_hicon;
+  if (impl->hicon_small)
+    GDI_CALL (DestroyIcon, (impl->hicon_small));
+  impl->hicon_small = small_hicon;
+}
+
+void          
+gdk_window_set_icon (GdkWindow *window, 
+                    GdkWindow *icon_window,
+                    GdkPixmap *pixmap,
+                    GdkBitmap *mask)
+{
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  /* do nothing, use gdk_window_set_icon_list instead */
 }
 
 void
index b2f07e79c2bb6e856430bd3e43d15da07d211e23..6561b54e8e0192e88d384243e21537ffc9cfabde 100644 (file)
@@ -76,7 +76,8 @@ struct _GdkWindowImplWin32
   GdkWin32PositionInfo position_info;
 
   HCURSOR hcursor;
-  HICON   hicon;
+  HICON   hicon_big;
+  HICON   hicon_small;
 
   /* Window size hints */
   gint hint_flags;